#ifndef _HJ212_CLIENT_DEF_H
#define _HJ212_CLIENT_DEF_H

#include <time.h>
#include <string.h>

#include "hj212_client_config.h"

#include "rtservice.h"
#include "gen_blkqueue.h"

#define HJ212_CLIENT_VERSIONS "v1.0.0"

struct hj212_client;
struct hj212_datastream;

enum hj212_value_enable_flag
{
    HJ212_ZSRTD_ENABLE = (1 << 0),   // 是否打包瞬时折算值
    HJ212_ZSHIS_ENABLE = (1 << 1),   // 是否打包历史数据折算值
    HJ212_COU_ENABLE = (1 << 2),     // 是否打包总量
    HJ212_HISFLAG_ENABLE = (1 << 3), // 历史数据是否打包flag
};
enum hj212_datamsg_type
{
    HJ212_MSG_TYPE_RTD = 0, // 实时数据
    HJ212_MSG_TYPE_MIN,     // 分钟数据
    HJ212_MSG_TYPE_HOUR,    // 小时数据
    HJ212_MSG_TYPE_DAY,     // 日数据
    HJ212_MSG_TYPE_NUM,
};
enum hj212_datastream_state
{
    HJ212_DATASTREAM_EMPTY = 0, // 数据流无数据
    HJ212_DATASTREAM_IDLE,      // 有数据并空闲，可以发送数据
    HJ212_DATASTREAM_BUSY,      // 数据流忙，一般为对方未响应
};
enum hj212_response_state
{
    HJ212_RESPONSE_IDLE = 0, // 空闲
    HJ212_RESPONSE_WAITINT,  // 正在等待
    // HJ212_RESPONSE_MATCH_SUCCESSFUL,    // 匹配成功
};
enum hj212_command
{
    GET_HJ212_SYS_CODE,        // 系统编码
    GET_HJ212_ACCESS_PWD,      // 访问密码
    GET_HJ212_CLIENT_MN,       // 客户端的MN
    GET_HJ212_PROTOCOL,        // 协议类型
    GET_HJ212_RTD_CYCLE,       // 实时周期 (秒)
    GET_HJ212_MIN_CYCLE,       // 分钟周期 (秒)
    GET_HJ212_HEARTBEAT_CYCLE, // 心跳周期 (秒)
    GET_HJ212_MAXRET,          // 重发次数
    GET_HJ212_SEND_INTER,      // 发送间隔 (毫秒)
    GET_HJ212_STREAM_TIMEOUT,  // 超时时间 (秒) (数据流等待回应的超时)

    SET_HJ212_SYS_CODE,        // 系统编码
    SET_HJ212_ACCESS_PWD,      // 访问密码
    SET_HJ212_CLIENT_MN,       // 客户端的MN
    SET_HJ212_PROTOCOL,        // 协议类型
    SET_HJ212_RTD_CYCLE,       // 实时周期 (秒)
    SET_HJ212_MIN_CYCLE,       // 分钟周期 (秒)
    SET_HJ212_HEARTBEAT_CYCLE, // 心跳周期 (秒)
    SET_HJ212_MAXRET,          // 重发次数
    SET_HJ212_SEND_INTER,      // 发送间隔 (毫秒)
    SET_HJ212_STREAM_TIMEOUT,  // 超时时间 (秒) (数据流等待回应的超时
};
enum hj212_protocol_type
{
    HJ212_PROTOCOL_2017 = 0,
    HJ212_PROTOCOL_2005,
};
/* 发送缓冲 */
struct send_buffer
{
    char mempool[HJ212_PACK_MAX_SIZE];
    rt_list_t list;
};

/* 编码参数 */
struct polcode_param
{
    char code[HJ212_POLCODE_MAX_LEN]; // 污染物因子的编码
    int codeid;                       // codeid，不一定需要
    int decimal_num;                  // 小数点位数
};
/* 数值结构 */
struct pol_rtval
{
    struct polcode_param param;

    float value;

    uint32_t enable_flag;
    float zs_value;

    uint32_t datamark;
};
struct pol_his_data
{
    struct polcode_param param;

    float min;   // 最小值
    float avg;   // 平均值
    float max;   // 最大值
    float cou;   // 周期总量值
    float total; // 累计总量值

    uint32_t enable_flag;

    float zs_min; // 最小值
    float zs_avg; // 平均值
    float zs_max; // 最大值

    uint32_t datamark;
};
/* msg基类 */
struct hj212_msg
{
    char qn[HJ212_QN_MAX_LEN];
    char st[HJ212_SYSCODE_MAX_LEN];
    int cn;
    char access_pwd[HJ212_ACCESS_PWD_MAX_LEN];
    char mn[HJ212_MN_MAX_LEN];
    int flag;
};
/* 通用的msg (主要用于除了数据之外的其他报文) */
struct hj212_generalmsg
{
    struct hj212_msg parent;
    char cp[HJ212_GENERAL_CP_MAX_LEN];
};
/* 带数据的msg (用于数据报文，只有数据报文才需要分包) */
struct hj212_datamsg
{
    struct hj212_msg parent;
    int pnum;
    int pno;
    time_t datatime;

    int type; // 数据类型 - 不同数据类型打包方式不一样
    struct gen_blk_queue queue;
};

/* 响应控制块 */
struct hj212_response;
typedef int (*hj212_response_match_t)(struct hj212_response *res, struct hj212_generalmsg *msg, uint32_t package_state, void *param);
typedef int (*hj212_response_timeout_t)(struct hj212_response *res, void *param);
struct hj212_response
{
    int cn;                            // 要求响应报文必须匹配的CN字段
    char qn[HJ212_QN_MAX_LEN];         // 要求响应报文必须匹配的QN字段
    char cp[HJ212_GENERAL_CP_MAX_LEN]; // 要求响应报文必须匹配的CP字段

    hj212_response_match_t match;
    void *match_param;

    hj212_response_timeout_t timeout_handle;
    void *timeout_param;
    time_t register_time;
    int timeout;

    int state; // 状态

    rt_list_t list;
};
/* 请求控制块 */
struct hj212_request;
typedef int (*request_handle_t)(struct hj212_client *client, struct hj212_request *request);
struct hj212_request
{
    char qn[HJ212_QN_MAX_LEN]; // 要求响应报文必须匹配的QN字段
    /* 处理机 */
    request_handle_t handle;

    rt_list_t list;
};

/* * 
 * 尝试匹配一个请求, 
 * 匹配成功时应该在这个函数中
 * 【创建请求控制块并插入到客户端请求列表】
 * 或者
 * 【进行必要的错误返回】 
 */
typedef int (*hj212_request_match)(struct hj212_client *client,
                                   struct hj212_generalmsg *msg,
                                   uint32_t package_state);

/* 数据流相关 */
struct hj212_datasource
{
    int (*is_empty)(struct hj212_datasource *source);
    int (*next)(struct hj212_datasource *source, struct hj212_datamsg *msg);
};
/* 数据流 */
struct hj212_datastream
{
    struct hj212_datamsg msg;        // 数据暂存
    struct hj212_response response;  // 响应
    struct hj212_datasource *source; // 数据源

    int type; // 数据流类型

    int maxret;  // 最大重发次数
    int count;   // 当前发送次数
    int itemnum; // 数据项数量
};
/* HJ212 客户端 */
struct hj212_client;
struct hj212_client_ops
{
    /* 系统相关 */
    int (*command)(struct hj212_client *client, int cmd, void *args); // 命令接口，暂时用于获取/设置系统参数
    time_t (*current_timestamp)(void);                                // 获取当前时间
    struct timeval (*current_subsec)(void);                           // 获取当前精确时间戳

    /* OS特性 */
    void (*lock)(struct hj212_client *client);
    int (*trylock)(struct hj212_client *client);
    void (*unlock)(struct hj212_client *client);

    /* 内存分配相关 */
    void *(*malloc)(size_t size);
    void *(*calloc)(unsigned int num, size_t size);
    void (*free)(void *ptr);
    /* 设备IO */
    int (*dev_open)(struct hj212_client *client, int flag); // 设备操作接口
    int (*dev_close)(struct hj212_client *client);
    int (*dev_state)(struct hj212_client *client);
    int (*dev_recv)(struct hj212_client *client, uint8_t *buffer, int len, int timeout);
    int (*dev_send)(struct hj212_client *client, const uint8_t *buffer, int len);

    /* 数据相关接口 */
    struct hj212_datasource *(*get_data_source)(struct hj212_client *client, int type);                                 // 获取主动上报的数据源
    struct hj212_datasource *(*create_hisdata_source)(struct hj212_client *client, int type, time_t begin, time_t end); // 创建历史数据的数据源(用于补足数据和上位机提取数据)
    void (*delete_data_source)(struct hj212_client *client, struct hj212_datasource *source);
};
struct hj212_client
{
    int id;
#if 0
    int login; // 登陆状态
#endif
    struct send_buffer *sendbuf;
    rt_list_t idle_sendbuf_list;   // 空闲发送缓冲块
    rt_list_t sendbuf_list;        // 待发送的缓冲块待
    struct timeval last_send_time; // 上一次发送的时间

    uint8_t recv_buffer[HJ212_RECV_BUFFER_SIZE]; // 接收字节流缓冲
    struct hj212_generalmsg recv_msg;            // 接收的消息缓冲

    struct hj212_datastream *stream[HJ212_MSG_TYPE_NUM]; // 主动上发的数据流(对应每种类型一种)
    uint32_t push_enable;

    struct hj212_datastream *trigger_stream[HJ212_MSG_TYPE_NUM]; // 外部触发的数据流

    time_t last_heartbeat_time; // 最近一条心跳数据的时间

    rt_list_t request_list;  // 请求队列，所有待处理的请求都应该在这里
    rt_list_t response_list; // 响应队列，所有待响应事件都应该在这里

    /* HJ212客户端的外部操作 */
    const struct hj212_client_ops *ops; // 需要实现的接口
    /* 以下所有变量皆为临时变量，函数内有效，不跨函数使用，定义在这里只是为了不频繁申请内存 */
    // uint8_t tmp_buffer[1024];
};
typedef struct hj212_client *hj212_client_t;

#endif
